package org.ytor.core.sysapi.user.logic;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.ytor.common.exception.BaseException;
import org.ytor.common.util.Colls;
import org.ytor.common.util.Strs;
import org.ytor.common.util.bean.Beans;
import org.ytor.core.auth.Identity;
import org.ytor.core.sqlflow.BaseLogic;
import org.ytor.core.sqlflow.SQLHelper;
import org.ytor.core.sqlflow.Page;
import org.ytor.core.sqlflow.builder.support.WhereBuilder;
import org.ytor.core.sqlflow.executor.DMLResult;
import org.ytor.core.sysapi.depart.repository.SysDepartRepository;
import org.ytor.core.sysapi.user.repository.SysUserDepartRepository;
import org.ytor.core.sysapi.user.repository.SysUserRoleRepository;
import org.ytor.core.sysapi.depart.model.SysDepart;
import org.ytor.core.sysapi.role.model.SysRole;
import org.ytor.core.sysapi.user.model.SysUserDepart;
import org.ytor.core.sysapi.user.model.SysUserRole;
import org.ytor.core.sysapi.login.req.CheckPasswordReq;
import org.ytor.core.sysapi.login.req.RefreshPasswordReq;
import org.ytor.core.sysapi.depart.resp.SysDepartResp;
import org.ytor.core.sysapi.user.resp.SysUserRoleResp;
import org.ytor.core.sysapi.user.model.SysUser;
import org.ytor.core.sysapi.user.req.SysUserReq;
import org.ytor.core.sysapi.user.resp.SysUserResp;
import org.ytor.core.sysapi.user.repository.SysUserRepository;
import org.ytor.core.util.Pages;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * created by yangtong on 2025/8/11 00:04:35
 * <br/>
 * User 模块逻辑层
 */
@Service
@RequiredArgsConstructor
public class SysUserLogic extends BaseLogic<SysUser, SysUserRepository> {

    private final SysUserRoleRepository userRoleRepo;
    private final SysUserDepartRepository userDepartRepo;
    private final SysDepartRepository departRepo;
    private final Identity identity;

    public Page<SysUserResp> queryPage(Integer pageNo, Integer pageSize, WhereBuilder where) {
        Page<SysUser> page = repository.queryPage(pageNo, pageSize, where);
        Page<SysUserResp> userRespIPage = Pages.transPage(page, SysUser::toResp);
        List<SysUserResp> records = userRespIPage.getRecords();
        // 查询每个用户的全部部门信息
        if (!records.isEmpty()) {
            List<String> userIds = records.stream().map(SysUserResp::getId).toList();
            List<SysDepartResp> sysUserDeparts = userDepartRepo.queryDepartByUserIds(userIds);
            Map<String, List<SysDepartResp>> userIdMap = sysUserDeparts.stream().collect(Collectors.groupingBy(SysDepartResp::getUserId));
            for (SysUserResp record : records) {
                record.setDepartList(userIdMap.get(record.getId()));
            }
        }
        return userRespIPage;
    }

    public List<SysRole> listAllRole(String userId) {
        return repository.listAllRoleByUserId(userId);
    }

    public List<SysUserRoleResp> listUserRoles(String userId, String roleName, String roleCode, String departIds) {
        List<String> departIdList = null;
        if (departIds != null) {
            departIdList = Arrays.stream(departIds.split(",")).filter(Strs::isNotEmpty).toList();
        }
        return repository.listUserRoles(userId, roleName, roleCode, departIdList);
    }

    public void updateUserRole(String userId, String roleId) {
        SysUserRole sysUserRole = SQLHelper.select()
                .from(SysUserRole.class)
                .where(w -> w.eq(SysUserRole::getUserId, userId).eq(SysUserRole::getRoleId, roleId))
                .limit(1)
                .one();

        //新增用户-角色关系
        if (sysUserRole == null) {
            sysUserRole = new SysUserRole();
            sysUserRole.setUserId(userId);
            sysUserRole.setRoleId(roleId);
            userRoleRepo.insert(sysUserRole);
        }
        //编辑用户-角色关系
        else {
            userRoleRepo.deleteById(sysUserRole.getId());
        }
    }

    public void addOrUpdate(SysUserReq userdata) {
        SysUser sysUser = Beans.copyProperties(userdata, SysUser.class);
        if (sysUser.getId() == null && Strs.isEmpty(sysUser.getPassword())) {
            sysUser.setPassword(identity.encode("123"));
        }
        DMLResult dmlResult = repository.insertOrUpdate(sysUser);

        syncDeparts(sysUser, userdata.getDepartList());
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteByIds(String ids) {
        if (Strs.isEmpty(ids)) {
            throw new BaseException("删除接口的ids不能为空");
        }
        List<String> idList = Arrays.asList(ids.split(","));
        repository.deleteById(idList);

        userDepartRepo.delete(w -> w.in(SysUserDepart::getUserId, idList));
    }

    public List<SysDepartResp> listUserDeparts(String userId) {
        SysUser sysUser = repository.queryById(userId);
        List<SysUserDepart> userDeparts = userDepartRepo.queryList(w -> w.eq(SysUserDepart::getUserId, userId));
        if (userDeparts.isEmpty()) {
            return Collections.emptyList();
        }
        List<String> departIds = userDeparts.stream().map(SysUserDepart::getDepartId).toList();

        List<SysDepart> departs = departRepo.queryById(departIds);

        return departs.stream().map(i -> {
            SysDepartResp resp = i.toResp();
            resp.setCurrentDepart(i.getDepartCode().equals(sysUser.getDepartCode()));
            return resp;
        }).toList();
    }

    public void updateUserCurrentDepart(String userId, String departCode) {
        List<SysDepartResp> departs = listUserDeparts(userId);
        boolean exist = departs.stream().anyMatch(i -> i.getDepartCode().equals(departCode));
        if (exist) {
            SQLHelper.update(SysUser.class)
                    .set(SysUser::getDepartCode, departCode)
                    .where(w -> w.eq(SysUser::getId, userId))
                    .submit();
        } else {
            throw new RuntimeException("分配的部门编码【" + departCode + "】不属于当前用户");
        }
    }

    public String checkPassword(CheckPasswordReq checkPasswordReq) {
        //获取用户当前密码
        SysUser sysUser = repository.queryById(checkPasswordReq.getUserId());
        String sourcePassword = sysUser.getPassword();

        //和传过来的密码比较
        if (identity.match(checkPasswordReq.getPassword(), sourcePassword)) {
            return null;
        }
        return "旧密码错误";
    }

    public void refreshPassword(RefreshPasswordReq refreshPasswordReq) {
        //密码校验
        CheckPasswordReq checkPasswordReq = new CheckPasswordReq();
        checkPasswordReq.setUserId(refreshPasswordReq.getUserId());
        checkPasswordReq.setPassword(refreshPasswordReq.getOldPassword());
        String msg = checkPassword(checkPasswordReq);
        if (msg != null) {
            throw new BaseException(msg);
        }

        //更新密码
        String newPassword = identity.encode(refreshPasswordReq.getNewPassword());
        SQLHelper.update(SysUser.class)
                .set(SysUser::getPassword, newPassword)
                .where(w -> w.eq(SysUser::getId, refreshPasswordReq.getUserId()))
                .submit();
    }

    private void syncDeparts(SysUser user, List<String> newDepartList) {
        String userId = user.getId();
        List<SysUserDepart> sysUserDeparts = userDepartRepo.queryList(w -> w.eq(SysUserDepart::getUserId, userId));
        List<String> oldDepartList = sysUserDeparts.stream().map(SysUserDepart::getDepartId).toList();
        // 要删除的元素
        List<String> deletedIds = Colls.diff(oldDepartList, newDepartList);
        // 检查要删除的元素中是否有用户当前元素
        String currentDepartCode = user.getDepartCode();
        SysDepart one = departRepo.select().where(w -> w.eq(SysDepart::getDepartCode, currentDepartCode)).limit(1).one();
        if (one != null) {
            if (deletedIds.stream().anyMatch(i -> i.equals(one.getId()))) {
                throw new RuntimeException("部门id【" + one.getId() + "】为用户【" + userId + "】的当前部门，无法删除");
            }
        }

        // 要新增的元素
        List<String> insertedIds = Colls.diff(newDepartList, oldDepartList);

        if (!deletedIds.isEmpty()) {
            for (String id : deletedIds) {
                userDepartRepo.delete(w -> w.eq(SysUserDepart::getUserId, id).eq(SysUserDepart::getDepartId, id));
            }
        }
        if (!insertedIds.isEmpty()) {
            for (String insertedId : insertedIds) {
                SysUserDepart userDepart = new SysUserDepart();
                userDepart.setUserId(userId);
                userDepart.setDepartId(insertedId);
                userDepartRepo.insert(userDepart);
            }
        }
    }

}
